package temp;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import java.util.Set;

//import yago.DataFromYAGO;



import dataset.DataEntry;
import dataset.Dataset;
import edu.stanford.nlp.ling.CoreLabel;
import edu.stanford.nlp.ling.CoreAnnotations.LemmaAnnotation;
import edu.stanford.nlp.ling.CoreAnnotations.PartOfSpeechAnnotation;
import edu.stanford.nlp.ling.CoreAnnotations.SentencesAnnotation;
import edu.stanford.nlp.ling.CoreAnnotations.TextAnnotation;
import edu.stanford.nlp.ling.CoreAnnotations.TokensAnnotation;
import edu.stanford.nlp.ling.IndexedWord;
import edu.stanford.nlp.pipeline.Annotation;
import edu.stanford.nlp.pipeline.StanfordCoreNLP;
import edu.stanford.nlp.trees.Tree;
import edu.stanford.nlp.trees.TreeCoreAnnotations.TreeAnnotation;
import edu.stanford.nlp.trees.semgraph.SemanticGraph;
import edu.stanford.nlp.trees.semgraph.SemanticGraphEdge;
import edu.stanford.nlp.trees.semgraph.SemanticGraphCoreAnnotations.CollapsedCCProcessedDependenciesAnnotation;
import edu.stanford.nlp.util.CoreMap;

//given a entry in dataset, identify the temporal relationship between  event and dates
public class TempIdentifier {
	//
	// just based on wether there is dependency between the time and the event to identify the temporal information
	
	StanfordCoreNLP pipeline;
	Set<String> reportingWords;
	
	public TempIdentifier(){
		Properties props = new Properties();
		props.put("annotators", "tokenize, ssplit, pos, lemma, ner, parse");
		this.pipeline = new StanfordCoreNLP(props);
		this.reportingWords = ReportingWords.reportingWords();
	}
	public DataEntry indentifyNERwithWindwoWithReports_andEnd(DataEntry queryEntry){
		DataEntry result = this.indentifyNER(queryEntry);
		for( int i=0; i<result.dates.size();i++){
			if( this.dateInWindowWithoutReport3(i, result)){
				result.related.set(i, "REL");
			}
		}
		return result;
	}
	
	public DataEntry indentifyNERwithWindwoWithReports_andThat(DataEntry queryEntry){
		DataEntry result = this.indentifyNER(queryEntry);
		for( int i=0; i<result.dates.size();i++){
			if( this.dateInWindowWithoutReport2(i, result)){
				result.related.set(i, "REL");
			}
		}
		return result;
	}
	public DataEntry indentifyNERwithWindwoWithReports1(DataEntry queryEntry){
		DataEntry result = this.indentifyNER(queryEntry);
		for( int i=0; i<result.dates.size();i++){
			if( this.dateInWindowWithoutReport1(i, result)){
				result.related.set(i, "REL");
			}
		}
		return result;
	}
	public DataEntry indentifyNERwithWindwoWithReports(DataEntry queryEntry){
		DataEntry result = this.indentifyNER(queryEntry);
		for( int i=0; i<result.dates.size();i++){
			if( this.dateInWindowWithoutReport(i, result)){
				result.related.set(i, "REL");
			}
		}
		return result;
	}
	public DataEntry indentifyNERwithWindow(DataEntry queryEntry){
		DataEntry result = this.indentifyNER(queryEntry);
		for( int i=0; i<result.dates.size();i++){
			if( this.dateInWindow(i, result)){
				result.related.set(i, "REL");
			}
		}
		return result;
	}
	//use NER information to idnetify
	public DataEntry indentifyNER(DataEntry queryEntry){

		String orig_sen = queryEntry.getOri_sentence();
		ArrayList<String> newrel = new ArrayList<String>();
		//initialize all false
		for( int i=0; i<queryEntry.related.size();i++){
			newrel.add("NON");
		}
		//parse this sentence
		
		//System.out.println("start");
		long t1 = System.currentTimeMillis();
		Annotation document = new Annotation(orig_sen);
	    this.pipeline.annotate(document);
	    List<CoreMap> sentences = document.get(SentencesAnnotation.class);
	    
	    for(CoreMap sentence: sentences) {
	  

	        SemanticGraph dependencies = sentence.get(CollapsedCCProcessedDependenciesAnnotation.class);
	        
	        Iterator<SemanticGraphEdge> itr = dependencies.edgeIterable().iterator();
	       
	        while( itr.hasNext()){
	        	SemanticGraphEdge edge = itr.next();
	        	IndexedWord source = edge.getSource();
	        	IndexedWord target = edge.getTarget();
	        	
	        	//System.out.println("**********");
	        	//System.out.println("source:"+source);
	        	//System.out.println("wether containRelation:"+ nodeContainRelation(queryEntry,source));
	        	//System.out.println("target:"+target);
	        	//System.out.println("wether containRelation:"+ nodeContainRelation(queryEntry,target));
	        	boolean containRelation = false;
	        	if( nodeContainRelation(queryEntry,source)||nodeContainRelation(queryEntry,target)){
	        		containRelation = true;
	        	}
	        	
	        	if( containRelation==false){
	        		continue;
	        	}
	        	
	        	for(int i=0;i<queryEntry.dates.size();i++){
	        		//System.out.println("wether source contain date "+i+" "+queryEntry.dates.get(i)+":"+nodeContainDates(i,queryEntry,source));
	        		//System.out.println("wether target contain date "+i+" "+queryEntry.dates.get(i)+":"+nodeContainDates(i,queryEntry,target));
	        		boolean containDate=false;
	        		//System.out.println("i:"+i);
	        		if( nodeContainDates(i,queryEntry,source)||nodeContainDates(i,queryEntry,target) ){
	        			containDate = true;
	        		//	System.out.println("contain Date");
	        		}
	        		if( containDate&&containRelation){
	        			newrel.set(i, "REL");
	        			//System.out.println("set i:"+i+" to REL");
	        		
	        			}
	        	}
	        	
	        	
	        	//##THIS PART SEEMS PROBLEMATIC
	        	//if a object is a LOC or then, find whether a date is relate to that LOC
	        	if( target.ner().equals("ORGANIZATION")||target.ner().equals("LOCATION") ){
	        		Iterator<SemanticGraphEdge> itr_1 = dependencies.edgeIterable().iterator();
        			while(itr_1.hasNext()){
        				SemanticGraphEdge edge_1 = itr_1.next();
        	        	IndexedWord source_1 = edge_1.getSource();
        	        	IndexedWord target_1 = edge_1.getTarget();	
        	        	
        	        	boolean containLoc = false;
        	        	if( nodeContainLoc(target,source_1)||nodeContainLoc(target,target_1)){
        	        		containLoc = true;
        	        	
        	        	}
        	        	if( containLoc==false){
        	        		continue;
        	        	}
        	        	
        	        	for(int i=0;i<queryEntry.dates.size();i++){
        	        		//System.out.println("wether source contain date "+i+" "+queryEntry.dates.get(i)+":"+nodeContainDates(i,queryEntry,source));
        	        		//System.out.println("wether target contain date "+i+" "+queryEntry.dates.get(i)+":"+nodeContainDates(i,queryEntry,target));
        	        		boolean containDate_1=false;
        	        		if( nodeContainDates(i,queryEntry,source_1)||nodeContainDates(i,queryEntry,target_1) ){
        	        			containDate_1 = true;
        	        		}
        	        		if( containDate_1&&containRelation&&containLoc){
        	        			newrel.set(i, "REL");
        	        		
        	        		}
        	        	}
        	        	
        			}
	        	}
	        	//System.out.println("*******");
	        }
	      }
	
		return new DataEntry(queryEntry.getTriple(),queryEntry.relation, queryEntry.dates, newrel);
	}
	public DataEntry indentify(DataEntry queryEntry){
		
		String orig_sen = queryEntry.getOri_sentence();
		ArrayList<String> newrel = new ArrayList<String>();
		//initialize all false
		for( int i=0; i<queryEntry.related.size();i++){
			newrel.add("NON");
		}
		//parse this sentence
		
		//System.out.println("start");
		long t1 = System.currentTimeMillis();
		Annotation document = new Annotation(orig_sen);
	    this.pipeline.annotate(document);
	    List<CoreMap> sentences = document.get(SentencesAnnotation.class);
	    
	    for(CoreMap sentence: sentences) {
	  

	        SemanticGraph dependencies = sentence.get(CollapsedCCProcessedDependenciesAnnotation.class);
	        
	        Iterator<SemanticGraphEdge> itr = dependencies.edgeIterable().iterator();
	       
	        while( itr.hasNext()){
	        	SemanticGraphEdge edge = itr.next();
	        	IndexedWord source = edge.getSource();
	        	IndexedWord target = edge.getTarget();
	        	
	        	//System.out.println("**********");
	        	//System.out.println("source:"+source);
	        	//System.out.println("wether containRelation:"+ nodeContainRelation(queryEntry,source));
	        	//System.out.println("target:"+target);
	        	//System.out.println("wether containRelation:"+ nodeContainRelation(queryEntry,target));
	        	boolean containRelation = false;
	        	
	        	System.out.println("queryEntry:"+queryEntry.getOri_sentence());
	        	System.out.println("Source:"+ source.lemma());
	        	System.out.println("target:"+ target.lemma());
	        	if( nodeContainRelation(queryEntry,source)||nodeContainRelation(queryEntry,target)){
	        		containRelation = true;
	        		System.out.println("Contain relation");
	        	}
	        	
	        	if( containRelation==false){
	        		System.out.println("not contain relation");
	        		continue;
	        	}
	        	
	        	for(int i=0;i<queryEntry.dates.size();i++){
	        		//System.out.println("wether source contain date "+i+" "+queryEntry.dates.get(i)+":"+nodeContainDates(i,queryEntry,source));
	        		//System.out.println("wether target contain date "+i+" "+queryEntry.dates.get(i)+":"+nodeContainDates(i,queryEntry,target));
	        		boolean containDate=false;
	        		System.out.println("i:"+i);
	        		if( nodeContainDates(i,queryEntry,source)||nodeContainDates(i,queryEntry,target) ){
	        			containDate = true;
	        			System.out.println("contain Date");
	        		}
	        		if( containDate&&containRelation){
	        			newrel.set(i, "REL");
	        			System.out.println("set i:"+i+" to REL");
	        		}
	        	}
	        	//System.out.println("*******");
	        }
	      }
	
		return new DataEntry(queryEntry.getTriple(),queryEntry.relation, queryEntry.dates, newrel);
	}
	
	
	public static boolean nodeContainRelation(DataEntry query, IndexedWord node){
		String relation = query.relation;
		
		//#assumen one sentence only contain one unique relation string
		int r_start = query.getOri_sentence().indexOf(relation);
		int r_end = r_start+relation.length(); 
		
		int n_start = node.beginPosition();
		int n_end = node.endPosition();
		
		if( r_start<=n_start&&n_end<=r_end){
			return true;
		}
		
		return false;
	}
	//check wether contain loc/org node
	
	public static boolean nodeContainLoc(IndexedWord loc, IndexedWord node){
		
		if(loc.originalText().equals(node.originalText())&&loc.beginPosition()==node.beginPosition()){
			return true;
		}else{
			return false;
		}
		
	}
	
	//check wether node contain the ith dates
	public static boolean nodeContainDates( int i,DataEntry query, IndexedWord node){
		
		
		
		String dateString = query.dates.get(i);
		String sen = query.getOri_sentence();
		//get the end pos of the last date string
		int d_start =-1;
		int d_end = -1;
		int pos =-1;
		int tmp_pos = -1;
		if( i>0 ){
			for( int j=0;j<i;j++){
				tmp_pos = sen.indexOf(query.dates.get(j),pos);
				pos = tmp_pos+query.dates.get(j).length();
			}
			
			d_start = sen.indexOf(dateString,pos);
			d_end = d_start+ dateString.length();
		}else{
			
			d_start = sen.indexOf(dateString,pos);
			d_end = d_start+ dateString.length();
		}
		
		int n_start = node.beginPosition();
		int n_end = node.endPosition();
		

		if( d_start<=n_start&&n_end<=d_end){
			return true;
		}
		
		return false;
	}
	
	public Dataset identifyAll(Dataset set){
		ArrayList<DataEntry> re_entries = new ArrayList<DataEntry>();
		int i = 0;
		for( DataEntry e:set.entries){
			//DataEntry re_e = this.indentify(e);
			//DataEntry re_e = this.indentifyNER(e);
			DataEntry re_e = this.indentifyNERwithWindow(e);
			//DataEntry re_e = this.indentifyNERwithWindwoWithReports1(e);
			re_entries.add(re_e);
			i++;
			System.out.println("Identify:"+i+"/"+set.entries.size()+" finished");
		}
		return new Dataset(re_entries);
	}
	public boolean dateInWindowWithoutReport(int i,DataEntry query){
		int window = 3;
		String sen = query.getSentence();
		int date_s = this.findStartOfDate(i, query);
		int date_e = date_s + query.dates.get(i).length();
		
		//start of first entity
		int e1_s = sen.indexOf("[[[");
		//end of the first entity
		int e1_e = sen.indexOf("]]]");
		//end of the second entity
		int e2_e = sen.indexOf("]]]",e1_e+3);
		
		if( date_e<e1_s){
			String between = sen.substring(date_e,e1_s);
			int num = this.wordsInString(between);
			if( num<window){
				String before = sen.substring(0,date_s);
				//see if before and between contain reporting words
				boolean report = this.containReporting(before, between, 2);
				if(report==false){
					return true;
				}
			}
		}else{
			if( date_s>e2_e){
				String between = sen.substring(e2_e,date_s);
				int num = this.wordsInString(between);
				if( num<window){
					return true;
				}
			}
		}
		
		return false;
	}
	//reporting and end of sen ,no that
	public boolean dateInWindowWithoutReport3(int i,DataEntry query){
		int window = 3;
		String sen = query.getSentence();
		int date_s = this.findStartOfDate(i, query);
		int date_e = date_s + query.dates.get(i).length();
		
		//start of first entity
		int e1_s = sen.indexOf("[[[");
		//end of the first entity
		int e1_e = sen.indexOf("]]]");
		//end of the second entity
		int e2_e = sen.indexOf("]]]",e1_e+3);
		
		if( date_e<e1_s){
			String between = sen.substring(date_e,e1_s);
			int num = this.wordsInString(between);
			if( num<window){
				String before = sen.substring(0,date_s);
				//see if before and between contain reporting words
				boolean report = this.containReporting(before, between, 2);
				
						if((report==false)){
							return true;
						}
			}
		}else{
			if( date_s>e2_e){
				String between = sen.substring(e2_e,date_s);
				int num = this.wordsInString(between);
				if( num<window){
					String after = sen.substring(date_e,sen.length());
					boolean report = this.containReporting(between, after, 2);
					if(report==false){
						return true;
					}
				}
			}
		}
		
		return false;
	}
	
	//reporiting and that no check the end of sen
	public boolean dateInWindowWithoutReport2(int i,DataEntry query){
		int window = 3;
		String sen = query.getSentence();
		int date_s = this.findStartOfDate(i, query);
		int date_e = date_s + query.dates.get(i).length();
		
		//start of first entity
		int e1_s = sen.indexOf("[[[");
		//end of the first entity
		int e1_e = sen.indexOf("]]]");
		//end of the second entity
		int e2_e = sen.indexOf("]]]",e1_e+3);
		
		if( date_e<e1_s){
			String between = sen.substring(date_e,e1_s);
			int num = this.wordsInString(between);
			if( num<window){
				String before = sen.substring(0,date_s);
				//see if before and between contain reporting words
				boolean report = this.containReporting(before, between, 2);
				boolean that = this.containThat(before, 2);
						if((report==false)&&(that==false)){
							return true;
						}
			}
		}else{
			if( date_s>e2_e){
				String between = sen.substring(e2_e,date_s);
				int num = this.wordsInString(between);
				if( num<window){
					
						return true;
					
				}
			}
		}
		
		return false;
	}
	public boolean dateInWindowWithoutReport1(int i,DataEntry query){
		int window = 3;
		String sen = query.getSentence();
		int date_s = this.findStartOfDate(i, query);
		int date_e = date_s + query.dates.get(i).length();
		
		//start of first entity
		int e1_s = sen.indexOf("[[[");
		//end of the first entity
		int e1_e = sen.indexOf("]]]");
		//end of the second entity
		int e2_e = sen.indexOf("]]]",e1_e+3);
		
		if( date_e<e1_s){
			String between = sen.substring(date_e,e1_s);
			int num = this.wordsInString(between);
			if( num<window){
				String before = sen.substring(0,date_s);
				//see if before and between contain reporting words
				boolean report = this.containReporting(before, between, 2);
				boolean that = this.containThat(before, 2);
						if((report==false)&&(that==false)){
							return true;
						}
			}
		}else{
			if( date_s>e2_e){
				String between = sen.substring(e2_e,date_s);
				int num = this.wordsInString(between);
				if( num<window){
					String after = sen.substring(date_e,sen.length());
					boolean report = this.containReporting(between, after, 2);
					if(report==false){
						return true;
					}
				}
			}
		}
		
		return false;
	}
	
	public boolean dateInWindow(int i,DataEntry query){
		
		int window = 3;
		String sen = query.getSentence();
		int date_s = this.findStartOfDate(i, query);
		int date_e = date_s + query.dates.get(i).length();
		
		//start of first entity
		int e1_s = sen.indexOf("[[[");
		//end of the first entity
		int e1_e = sen.indexOf("]]]");
		//end of the second entity
		int e2_e = sen.indexOf("]]]",e1_e+3);
		
		if( date_e<e1_s){
			String between = sen.substring(date_e,e1_s);
			int num = this.wordsInString(between);
			if( num<window){
				return true;
			}
		}else{
			if( date_s>e2_e){
				String between = sen.substring(e2_e,date_s);
				int num = this.wordsInString(between);
				if( num<window){
					return true;
				}
			}
		}
		
		return false;
	}
	public boolean containThat(String before, int window){
		String[] bs = before.split(" ");
		int wc1=0;
		for(int i=bs.length-1; i>=0; i--){
			String b = bs[i];
			if(!b.equals("")&&!b.equals(" ")){
				if(wc1>window){
					break;
				}else{
					if( b.equals("that")){
						return true;
					}
					wc1++;
				}
			} 
		}
		return false;
	}
	public boolean containReporting(String before, String after, int window){
		String[] bs = before.split(" ");
		int wc1=0;
		for(int i=bs.length-1; i>=0; i--){
			String b = bs[i];
			if(!b.equals("")&&!b.equals(" ")){
				if(wc1>window){
					break;
				}else{
					if( this.reportingWords.contains(b)){
						return true;
					}
					wc1++;
				}
			}
		}
		
		String [] as = after.split(" ");
		int wc2 =0;
		for( int i=0;i<as.length;i++){
			String a = as[i];
			if(!a.equals("")&&!a.equals(" ")){
				if(wc2>window){
					break;
				}else{
					if( this.reportingWords.contains(a)){
						return true;
					}
					wc2++;
				}
			}
		}
		
		return false;
		
	}
	public int wordsInString(String s){
		String[] ws = s.split(" ");
		int count = 0;
		for( String w:ws){
			if( !w.equals("")){
				count++;
			}
		}
		return count;
	}
	
	public int findStartOfDate(int i,DataEntry query){
		
		String sen = query.getSentence();
		
		int s_pos = -1;
		for(int j=0;j<i;j++){
			s_pos = sen.indexOf(query.dates.get(j),s_pos);
			s_pos = s_pos+query.dates.get(j).length();
		}
		
		s_pos = sen.indexOf(query.dates.get(i),s_pos);
		return s_pos;
		
		
	}
	public static void main(String[]args) throws Exception{
		//String sen = "WASHINGTON _ Following are statements made Friday and Thursday by Lawrence Wechsler , a lawyer for the White House secretary , Betty Currie ; the White House ; White House spokesman Mike McCurry , and President Clinton in response to an article in The New York Times on Friday about her statements regarding a meeting with the president : Wechsler on Thursday `` Without commenting on the allegations raised in this article , to the extent that there is any implication or suggestion that Mrs. Currie was aware of any legal or ethical impropriety by anyone , that implication or suggestion is entirely inaccurate . ''";
		//System.out.println(sen.indexOf("statements",-1));
		//System.out.println(sen.length() );
		
		TempIdentifier tid = new TempIdentifier();
		//DataFromYAGO dfy = new DataFromYAGO();
		//Dataset bin_set = dfy.genDataSet();
		//Dataset bin_set = Dataset.dataFromText("/largedata1/cmput696/students/lyao1/sogodata/2data/dataset.txt");
		Dataset bin_set = Dataset.dataFromDir("/largedata1/cmput696/students/lyao1/sogodata/2data/dataset");
		/*for( DataEntry e:set.entries){
			if( e.relation.equals("conferred in")){
				System.out.println(e.tri.getOri_sentence());
				tid.indentify(e);l
			}
		}*/
		
		
		Dataset query_set = bin_set.queryDataSet();
		
		//ArrayList<DataEntry> as  = new ArrayList<DataEntry>();
		//as.add(bin_set.entries.get(3));
		//Dataset nd = new Dataset(as);
		//Dataset nq = nd.queryDataSet();
		
		Dataset res_set = tid.identifyAll(query_set);
		//Dataset res = tid.identifyAll(nq);
		
		bin_set.precision(res_set);
		bin_set.recall(res_set);
		bin_set.actual_precision(res_set);
		res_set.toText("/largedata1/cmput696/students/lyao1/sogodata/2data/tempRes.txt");
		bin_set.false_negatives(res_set,"/largedata1/cmput696/students/lyao1/sogodata/2data/falseNegatives.txt" );
		bin_set.false_positives(res_set, "/largedata1/cmput696/students/lyao1/sogodata/2data/falsePositives.txt");
		 //nd.precision(res);
		 //nd.recall(res);
		
		///write test , to test two contain functions,using the tow Friday and two Thursday one
	}
}
